package compiler.ast;

import java.io.PrintStream;
import java.util.ArrayList;

import compiler.tac.BasicBlock;
import compiler.tac.ExitBlock;
import compiler.tac.ThreeAddressCode;

public class WhileStatement extends Statement {
	Relation relation;
	ArrayList<Statement> body;
	
	public WhileStatement(Relation rel, ArrayList<Statement> body) {
		this.relation = rel;
		this.body = body;
	}

	public void printDotFormat(PrintStream out, String node) {
		out.println(node+" [label=\"while\"];");
		
		out.println(node+"->"+node+"0;");		
		relation.printDotFormat(out, node+0);

		String bodyNode = node+"1";
		out.println(node+"->"+bodyNode+";");
		out.println(bodyNode+" [label=\"body\"];");
		int order = 0;
		for (Statement stmt : body) {
			out.println(bodyNode+"->"+bodyNode+order+";");
			stmt.printDotFormat(out, bodyNode+order);
			order++;
		}
	}

	@Override
	public BasicBlock toThreeAddressCode(ThreeAddressCode tac, BasicBlock prev,
			ExitBlock exit) {
		// body block
		BasicBlock firstb = new BasicBlock();
		BasicBlock bodyb = firstb;
		tac.addBlock(bodyb);
		for (Statement stmt : body) {
			bodyb = stmt.toThreeAddressCode(tac, bodyb, exit);
			
			if (bodyb == null) {
				break;
			}
		}
		
		// condition block
		BasicBlock condb;
		if (bodyb.size() == 0) {
			condb = bodyb;
		} else {
			condb = new BasicBlock();
			tac.addBlock(condb);
			BasicBlock.add(bodyb, condb);
		}
		String t = relation.toThreeAddressCode(tac, condb);
		String conLable = tac.getLable();
		condb.addBranchInstruction(relation.getBranchOprt(), t, firstb, conLable);
		BasicBlock.add(condb, firstb);
		
		// add jump instruction in the previous block
		conLable = tac.getLable();
		prev.addJumpInstruction(condb,conLable);
		BasicBlock.add(prev, condb);
		
		// next block
		BasicBlock next = new BasicBlock();
		tac.addBlock(next);
		BasicBlock.add(condb, next);
		
		return next;
	}
}